// DRBT changes here

/*
 Copyright (c) 1997, 1998 Carnegie Mellon University.  All Rights
 Reserved. 

 Permission to use, copy, modify, and distribute this
 software and its documentation is hereby granted (including for
 commercial or for-profit use), provided that both the copyright notice and this permission notice appear in all copies of the software, derivative works, or modified versions, and any portions thereof, and that both notices appear in supporting documentation, and that credit is given to Carnegie Mellon University in all publications reporting on direct or indirect use of this code or its derivatives.

 ALL CODE, SOFTWARE, PROTOCOLS, AND ARCHITECTURES DEVELOPED BY THE CMU
 MONARCH PROJECT ARE EXPERIMENTAL AND ARE KNOWN TO HAVE BUGS, SOME OF
 WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS
 SOFTWARE OR OTHER INTELLECTUAL PROPERTY IN ITS ``AS IS'' CONDITION,
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE OR
 INTELLECTUAL PROPERTY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 DAMAGE.

 Carnegie Mellon encourages (but does not require) users of this
 software or intellectual property to return any improvements or
 extensions that they make, and to grant Carnegie Mellon the rights to redistribute these changes without encumbrance.

 The AODV code developed by the CMU/MONARCH group was optimized and tuned by Samir Das and Mahesh Marina, University of Cincinnati. The work was partially done in Sun Microsystems. Modified for gratuitous replies by Anant Utgikar, 09/16/02.

 */

//#include <ip.h>

#include <aodv/aodv.h>
#include <aodv/aodv_packet.h>
#include <random.h>
#include <cmu-trace.h>
//#include <energy-model.h>

// 1. DRBT
#include <math.h>
// end 1

#define max(a,b)        ( (a) > (b) ? (a) : (b) )
#define CURRENT_TIME    Scheduler::instance().clock()
#define DEBIT_MIN 5699

//#define DEBUG
//#define ERROR
#ifdef DEBUG
static int extra_route_reply = 0;
static int limit_route_request = 0;
static int route_request = 0;
#endif

/*
 TCL Hooks
 */

// 2. DRBT
/****** Global Variable *********/
Band_Aodv *bande_aodv = (Band_Aodv *)malloc(sizeof(Band_Aodv));
Band_Aodv *bande_qos = (Band_Aodv *)malloc(sizeof(Band_Aodv));
Band_Aodv *bande_BE = (Band_Aodv *)malloc(sizeof(Band_Aodv));
Band_Bef *bande_bef = (Band_Bef *)malloc(sizeof(Band_Bef));
int id_flux = 1; /* Identifiant flux : unique pour chaque transmission */
float bp_conlai = 1700; // Minh test
// end 2

int hdr_aodv::offset_;

static class AODVHeaderClass : public PacketHeaderClass {
public:
	AODVHeaderClass() :
		PacketHeaderClass("PacketHeader/AODV", sizeof(hdr_all_aodv)) {
		bind_offset(&hdr_aodv::offset_);
	}
} class_rtProtoAODV_hdr;

static class AODVclass : public TclClass {
public:
	AODVclass() :
		TclClass("Agent/AODV") {
	}
	TclObject* create(int argc, const char*const* argv) {
		assert(argc == 5);
		//return (new AODV((nsaddr_t) atoi(argv[4])));
		return (new AODV((nsaddr_t) Address::instance().str2addr(argv[4])));
	}
} class_rtProtoAODV;

int AODV::command(int argc, const char*const* argv) {
	// 3. DRBT  
	//Tcl& tcl = Tcl::instance();
	if (argc == 5) {
		Tcl& tcl = Tcl::instance();
		if (strcmp(argv[1], "findRoute") == 0) {
			//desire = (float)atoi(argv[4]);
			//source = (int)atoi(argv[2]);
			//dest   = (int)atoi(argv[3]);
			//printf("ID FLUX %d\n",(int)atoi(argv[5]));
			insertband(&bande_qos, (int)atoi(argv[2]), (int)atoi(argv[3]),
					(float)atoi(argv[4]));
			//afficheband(bande_qos);
			return TCL_OK;
		}
	}

	if (argc == 5) {
		Tcl& tcl = Tcl::instance();
		if (strcmp(argv[1], "findRoute_be") == 0) {
			//printf("SRC %d DST %d BP %f\n",(int)atoi(argv[2]),(int)atoi(argv[3]),(float)atoi(argv[4]));

			insertband(&bande_BE, (int)atoi(argv[2]), (int)atoi(argv[3]),
					(float)atoi(argv[4]));
			//afficheband(bande_BE);
			return TCL_OK;
		}
	}

	/*
	 *   Detection de l'évennement stop des flux Qos
	 */

	if (argc == 4) {
		Tcl& tcl = Tcl::instance();
		//if(strcmp(argv[0], "$cbr1") == 0) {
		if (strcmp(argv[1], "CasseRoute") == 0) {

			printf("Stop : ok %d \n", (int)(atoi)(argv[2]));
			if (index == (int)(atoi)(argv[2]))
				testFlux = (int)(atoi)(argv[3]);
			return TCL_OK;
		}
		//}

	}
	// end 3
	if (argc == 2) {
		Tcl& tcl = Tcl::instance();

		if (strncasecmp(argv[1], "id", 2) == 0) {
			tcl.resultf("%d", index);
			return TCL_OK;
		}

		// 4. DRBT
		if (strncasecmp(argv[1], "start", 5) == 0) {
			// end 4
			//printf("Start: ok\n");

			btimer.handle((Event*) 0);

			//#ifndef AODV_LINK_LAYER_DETECTION
			htimer.handle((Event*) 0);
			ntimer.handle((Event*) 0);
			//#endif // LINK LAYER DETECTION

			rtimer.handle((Event*) 0);
			return TCL_OK;
		}

	} else if (argc == 3) {
		if (strcmp(argv[1], "index") == 0) {
			index = atoi(argv[2]);
			return TCL_OK;
		}

		else if (strcmp(argv[1], "log-target") == 0 || strcmp(argv[1],
				"tracetarget") == 0) {
			logtarget = (Trace*) TclObject::lookup(argv[2]);
			if (logtarget == 0)
				return TCL_ERROR;
			return TCL_OK;
		} else if (strcmp(argv[1], "drop-target") == 0) {
			int stat = rqueue.command(argc, argv);
			if (stat != TCL_OK)
				return stat;
			return Agent::command(argc, argv);
		} else if (strcmp(argv[1], "if-queue") == 0) {
			ifqueue = (PriQueue*) TclObject::lookup(argv[2]);

			if (ifqueue == 0)
				return TCL_ERROR;
			return TCL_OK;
		} else if (strcmp(argv[1], "port-dmux") == 0) {
			dmux_ = (PortClassifier *)TclObject::lookup(argv[2]);
			if (dmux_ == 0) {
				fprintf(stderr, "%s: %s lookup of %s failed\n",__FILE__ ,
				argv[1], argv[2]);
				return TCL_ERROR;
			}
			return TCL_OK;
		}
	}
	return Agent::command(argc, argv);
}

/* 
 Constructor
 */

AODV::AODV(nsaddr_t id) :
	Agent(PT_AODV), btimer(this), htimer(this), ntimer(this), rtimer(this),
			lrtimer(this), rqueue() {

	index = id;
	seqno = 2;
	bid = 1;

	LIST_INIT(&nbhead);
	LIST_INIT(&bihead);

	logtarget = 0;
	ifqueue = 0;

	// 5. DRBT
	nbFlux_be = 0;
	compteur_be = 0;
	compteur_be_sc = 0;

	mapile = NULL;
	mapile_be = NULL;
	debitQoS = -1;
	emetteur = -1;
	bplibre_ = -1;

	testStCachees = false;
	testFlux = 0;

	minBp = DEBIT_MIN; // ? why
	//tailleFluxQoS = 0;
	// end 5
}

/*
 Timers
 */

void BroadcastTimer::handle(Event*) {
	agent->id_purge();
	Scheduler::instance().schedule(this, &intr, BCAST_ID_SAVE);
}

void HelloTimer::handle(Event*) {
	agent->sendHello();
	double interval = MinHelloInterval + ((MaxHelloInterval - MinHelloInterval)
			* Random::uniform());
	assert(interval >= 0);
	Scheduler::instance().schedule(this, &intr, interval);
}

void NeighborTimer::handle(Event*) {
	agent->nb_purge();
	Scheduler::instance().schedule(this, &intr, HELLO_INTERVAL);
}

void RouteCacheTimer::handle(Event*) {
	agent->rt_purge();
#define FREQUENCY 0.5 // sec
	Scheduler::instance().schedule(this, &intr, FREQUENCY);
}

void LocalRepairTimer::handle(Event* p) { // SRD: 5/4/99
	aodv_rt_entry *rt;
	struct hdr_ip *ih = HDR_IP( (Packet *)p);

	/* you get here after the timeout in a local repair attempt */
	/*	fprintf(stderr, "%s\n", __FUNCTION__); */

	rt = agent->rtable.rt_lookup(ih->daddr());

	if (rt && rt->rt_flags != RTF_UP) {
		// route is yet to be repaired
		// I will be conservative and bring down the route
		// and send route errors upstream.
		/* The following assert fails, not sure why */
		/* assert (rt->rt_flags == RTF_IN_REPAIR); */

		//rt->rt_seqno++;
		agent->rt_down(rt);
		// send RERR
#ifdef DEBUG
		fprintf(stderr,"Node %d: Dst - %d, failed local repair\n",index, rt->rt_dst);
#endif      
	}
	Packet::free((Packet *)p);
}

/*
 Broadcast ID Management  Functions
 */

void AODV::id_insert(nsaddr_t id, u_int32_t bid) {
	BroadcastID *b = new BroadcastID(id, bid);

	assert(b);
	b->expire = CURRENT_TIME + BCAST_ID_SAVE;
	LIST_INSERT_HEAD(&bihead, b, link);
}

/* SRD */
bool AODV::id_lookup(nsaddr_t id, u_int32_t bid) {
	BroadcastID *b = bihead.lh_first;

	// Search the list for a match of source and bid
	for (; b; b = b->link.le_next) {
		if ((b->src == id) && (b->id == bid))
			return true;
	}
	return false;
}

void AODV::id_purge() {
	BroadcastID *b = bihead.lh_first;
	BroadcastID *bn;
	double now= CURRENT_TIME;

	for (; b; b = bn) {
		bn = b->link.le_next;
		if (b->expire <= now) {
			LIST_REMOVE(b, link);
			delete b;
		}
	}
}

/*
 Helper Functions
 */

double AODV::PerHopTime(aodv_rt_entry *rt) {
	int num_non_zero = 0, i;
	double total_latency = 0.0;

	if (!rt)
		return ((double) NODE_TRAVERSAL_TIME );

	for (i=0; i < MAX_HISTORY; i++) {
		if (rt->rt_disc_latency[i] > 0.0) {
			num_non_zero++;
			total_latency += rt->rt_disc_latency[i];
		}
	}
	if (num_non_zero > 0)
		return (total_latency / (double) num_non_zero);
	else
		return ((double) NODE_TRAVERSAL_TIME);

}

/*
 Link Failure Management Functions
 */

static void aodv_rt_failed_callback(Packet *p, void *arg) {
	((AODV*) arg)->rt_ll_failed(p);
}

/*
 * This routine is invoked when the link-layer reports a route failed.
 */
void AODV::rt_ll_failed(Packet *p) {
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	aodv_rt_entry *rt;
	nsaddr_t broken_nbr = ch->next_hop_;

#ifndef AODV_LINK_LAYER_DETECTION
	drop(p, DROP_RTR_MAC_CALLBACK);
#else 

	/*
	 * Non-data packets and Broadcast Packets can be dropped.
	 */
	if(! DATA_PACKET(ch->ptype()) ||
			(u_int32_t) ih->daddr() == IP_BROADCAST) {
		drop(p, DROP_RTR_MAC_CALLBACK);
		return;
	}
	log_link_broke(p);
	if((rt = rtable.rt_lookup(ih->daddr())) == 0) {
		drop(p, DROP_RTR_MAC_CALLBACK);
		return;
	}
	log_link_del(ch->next_hop_);

#ifdef AODV_LOCAL_REPAIR
	/* if the broken link is closer to the dest than source, 
	 attempt a local repair. Otherwise, bring down the route. */

	if (ch->num_forwards()> rt->rt_hops) {
		local_rt_repair(rt, p); // local repair
		// retrieve all the packets in the ifq using this link,
		// queue the packets for which local repair is done, 
		return;
	}
	else
#endif // LOCAL REPAIR	
	{
		drop(p, DROP_RTR_MAC_CALLBACK);
		// Do the same thing for other packets in the interface queue using the
		// broken link -Mahesh
		while((p = ifqueue->filter(broken_nbr))) {
			drop(p, DROP_RTR_MAC_CALLBACK);
		}
		nb_delete(broken_nbr);
	}

#endif // LINK LAYER DETECTION
}

/*
 *  Eviter la reconstruction de route
 */

void AODV::handle_link_failure(nsaddr_t id) {
	// 6. DRBT
	/*
	 aodv_rt_entry *rt, *rtn;
	 Packet *rerr = Packet::alloc();
	 struct hdr_aodv_error *re = HDR_AODV_ERROR(rerr);

	 re->DestCount = 0;
	 for(rt = rtable.head(); rt; rt = rtn) {  // for each rt entry
	 rtn = rt->rt_link.le_next; 
	 if ((rt->rt_hops != INFINITY2) && (rt->rt_nexthop == id) ) {
	 assert (rt->rt_flags == RTF_UP);
	 assert((rt->rt_seqno%2) == 0);
	 rt->rt_seqno++;
	 re->unreachable_dst[re->DestCount] = rt->rt_dst;
	 re->unreachable_dst_seqno[re->DestCount] = rt->rt_seqno;
	 #ifdef DEBUG
	 fprintf(stderr, "%s(%f): %d\t(%d\t%u\t%d)\n", __FUNCTION__, CURRENT_TIME,
	 index, re->unreachable_dst[re->DestCount],
	 re->unreachable_dst_seqno[re->DestCount], rt->rt_nexthop);
	 #endif // DEBUG
	 re->DestCount += 1;
	 rt_down(rt);
	 }
	 // remove the lost neighbor from all the precursor lists
	 rt->pc_delete(id);
	 }   

	 if (re->DestCount > 0) {
	 #ifdef DEBUG
	 fprintf(stderr, "%s(%f): %d\tsending RERR...\n", __FUNCTION__, CURRENT_TIME, index);
	 #endif // DEBUG
	 sendError(rerr, false);
	 }
	 else {
	 Packet::free(rerr);
	 }
	 */
	// end 6
}

void AODV::local_rt_repair(aodv_rt_entry *rt, Packet *p) {
#ifdef DEBUG
	fprintf(stderr,"%s: Dst - %d\n", __FUNCTION__, rt->rt_dst);
#endif  
	// Buffer the packet 
	rqueue.enque(p);

	// mark the route as under repair 
	rt->rt_flags = RTF_IN_REPAIR;

	sendRequest(rt->rt_dst);

	// set up a timer interrupt
	Scheduler::instance().schedule(&lrtimer, p->copy(), rt->rt_req_timeout);
}

void AODV::rt_update(aodv_rt_entry *rt, u_int32_t seqnum, u_int16_t metric,
		nsaddr_t nexthop, double expire_time) {

	rt->rt_seqno = seqnum;
	rt->rt_hops = metric;
	rt->rt_flags = RTF_UP;
	rt->rt_nexthop = nexthop;
	rt->rt_expire = expire_time;
}

void AODV::rt_down(aodv_rt_entry *rt) {
	/*
	 *  Make sure that you don't "down" a route more than once.
	 */

	if (rt->rt_flags == RTF_DOWN) {
		return;
	}

	// assert (rt->rt_seqno%2); // is the seqno odd?
	rt->rt_last_hop_count = rt->rt_hops;
	rt->rt_hops = INFINITY2;
	rt->rt_flags = RTF_DOWN;
	rt->rt_nexthop = 0;
	rt->rt_expire = 0;

} /* rt_down function */

/*
 Route Handling Functions
 */

void AODV::rt_resolve(Packet *p) {
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	aodv_rt_entry *rt;

	/*
	 *  Set the transmit failure callback.  That
	 *  won't change.
	 */
	ch->xmit_failure_ = aodv_rt_failed_callback;
	ch->xmit_failure_data_ = (void*) this;
	rt = rtable.rt_lookup(ih->daddr());
	if (rt == 0) {
		rt = rtable.rt_add(ih->daddr());
	}

	/*
	 * If the route is up, forward the packet 
	 */

	if (rt->rt_flags == RTF_UP) {
		assert(rt->rt_hops != INFINITY2);
		forward(rt, p, NO_DELAY);
	}
	/*
	 *  if I am the source of the packet, then do a Route Request.
	 */
	else if (ih->saddr() == index) {
		rqueue.enque(p);
		sendRequest(rt->rt_dst);
	}
	/*
	 *	A local repair is in progress. Buffer the packet. 
	 */
	else if (rt->rt_flags == RTF_IN_REPAIR) {
		rqueue.enque(p);
	}

	/*
	 * I am trying to forward a packet for someone else to which
	 * I don't have a route.
	 */
	else {
		Packet *rerr = Packet::alloc();
		struct hdr_aodv_error *re = HDR_AODV_ERROR(rerr);
		/* 
		 * For now, drop the packet and send error upstream.
		 * Now the route errors are broadcast to upstream
		 * neighbors - Mahesh 09/11/99
		 */

		assert(rt->rt_flags == RTF_DOWN);
		re->DestCount = 0;
		re->unreachable_dst[re->DestCount] = rt->rt_dst;
		re->unreachable_dst_seqno[re->DestCount] = rt->rt_seqno;
		re->DestCount += 1;
#ifdef DEBUG
		fprintf(stderr, "%s: sending RERR...\n", __FUNCTION__);
#endif
		sendError(rerr, false);

		drop(p, DROP_RTR_NO_ROUTE);
	}

}

void AODV::rt_purge() {
	aodv_rt_entry *rt, *rtn;
	double now= CURRENT_TIME;
	double delay = 0.0;
	Packet *p;

	for (rt = rtable.head(); rt; rt = rtn) { // for each rt entry
		rtn = rt->rt_link.le_next;
		if ((rt->rt_flags == RTF_UP) && (rt->rt_expire < now)) {
			// if a valid route has expired, purge all packets from 
			// send buffer and invalidate the route.                    
			assert(rt->rt_hops != INFINITY2);
			while ((p = rqueue.deque(rt->rt_dst))) {
#ifdef DEBUG
				fprintf(stderr, "%s: calling drop()\n",
						__FUNCTION__);
#endif // DEBUG
				drop(p, DROP_RTR_NO_ROUTE);
			}
			rt->rt_seqno++;
			assert(rt->rt_seqno%2);
			rt_down(rt);
		} else if (rt->rt_flags == RTF_UP) {
			// If the route is not expired,
			// and there are packets in the sendbuffer waiting,
			// forward them. This should not be needed, but this extra 
			// check does no harm.
			assert(rt->rt_hops != INFINITY2);
			while ((p = rqueue.deque(rt->rt_dst))) {
				forward(rt, p, delay);
				delay += ARP_DELAY;
			}
		} else if (rqueue.find(rt->rt_dst))
			// If the route is down and 
			// if there is a packet for this destination waiting in
			// the sendbuffer, then send out route request. sendRequest
			// will check whether it is time to really send out request
			// or not.
			// This may not be crucial to do it here, as each generated 
			// packet will do a sendRequest anyway.

			sendRequest(rt->rt_dst);
	}

}

/*
 Packet Reception Routines
 */

void AODV::recv(Packet *p, Handler*) {
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);

	//printf("fid_ %d\n",ih->fid_);

	assert(initialized());
	//assert(p->incoming == 0);
	// XXXXX NOTE: use of incoming flag has been depracated; In order to track direction of pkt flow, direction_ in hdr_cmn is used instead. see packet.h for details.

	if (ch->ptype() == PT_AODV) {
		ih->ttl_ -= 1;
		recvAODV(p);
		return;
	}

	/*
	 *  Must be a packet I'm originating...
	 */
	if ((ih->saddr() == index) && (ch->num_forwards() == 0)) {
		/*
		 * Add the IP Header
		 */
		ch->size() += IP_HDR_LEN;
		// Added by Parag Dadhania && John Novatnack to handle broadcasting
		if ( (u_int32_t)ih->daddr() != IP_BROADCAST)
			ih->ttl_ = NETWORK_DIAMETER;
	}
	/*
	 *  I received a packet that I sent.  Probably
	 *  a routing loop.
	 */
	else if (ih->saddr() == index) {
		drop(p, DROP_RTR_ROUTE_LOOP);
		return;
	}
	/*
	 *  Packet I'm forwarding...
	 */
	else {
		/*
		 *  Check the TTL.  If it is zero, then discard.
		 */
		if (--ih->ttl_ == 0) {
			drop(p, DROP_RTR_TTL);
			return;
		}
	}
	// Added by Parag Dadhania && John Novatnack to handle broadcasting
	if ( (u_int32_t)ih->daddr() != IP_BROADCAST)
		rt_resolve(p);
	else
		forward((aodv_rt_entry*) 0, p, NO_DELAY);
}

void AODV::recvAODV(Packet *p) {
	struct hdr_aodv *ah = HDR_AODV(p);
	struct hdr_ip *ih = HDR_IP(p);

	assert(ih->sport() == RT_PORT);
	assert(ih->dport() == RT_PORT);

	/*
	 * Incoming Packets.
	 */
	switch (ah->ah_type) {

	case AODVTYPE_RREQ:
		recvRequest(p);
		break;

	case AODVTYPE_RREP:
		recvReply(p);
		break;

	case AODVTYPE_RERR:
		recvError(p);
		break;

	case AODVTYPE_HELLO:
		recvHello(p);
		break;

	default:
		fprintf(stderr, "Invalid AODV type (%x)\n", ah->ah_type);
		exit(1);
	}

}

void AODV::recvRequest(Packet *p) {
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_request *rq = HDR_AODV_REQUEST(p);
	aodv_rt_entry *rt;

	// 7. DRBT
	float bplibre; //Pour le control d'admission
	//float bplibre2;
	//float bplibre3; //Pour L'estimation de la bande restante dans mon lien
	float bpBE;
	float hops;
	float bp_requis; //Prendre en compte le multi-sauts 
	int idFlux = -1;
	// end 7

	/*
	 * Drop if:
	 *      - I'm the source
	 *      - I recently heard this request.
	 */

	if (rq->rq_src == index) {
#ifdef DEBUG
		fprintf(stderr, "%s: got my own REQUEST\n", __FUNCTION__);
#endif // DEBUG
		Packet::free(p);
		return;
	}

	if (id_lookup(rq->rq_src, rq->rq_bcast_id)) {

#ifdef DEBUG
		fprintf(stderr, "%s: discarding request\n", __FUNCTION__);
#endif // DEBUG
		Packet::free(p);
		return;
	}

	// 8. DRBT
	/*
	 *   Hops Number
	 */

	if (rq->rq_bp != -1) {
		hops = NETWORK_DIAMETER - ih->ttl_;
		if (hops >= 4)
			hops = 4;

		/*
		 *   Admission Control : Désactiver
		 */
		bp_requis = rq->rq_bp*hops;
		//afficheband(bande_aodv);
		bplibre = findband(bande_aodv, ih->saddr(), index);
		//printf("Je suis %d recv RREQ de %d de %d vers %d avec %f Nombre Hops %f requis %f libre%f\n",index,rq->rq_src,ih->saddr(),rq->rq_dst,rq->rq_bp,hops,bp_requis,bplibre);
		if (bp_requis > bplibre) {
			printf(
					"Je suis (%d) False Control Admission bp_requis (%f) > capacite (%f)\n",
					index, bp_requis, bplibre);
			//Packet::free(p);
			//return;
		}
	}
	// end 8

	/*
	 * Cache the broadcast ID
	 */
	id_insert(rq->rq_src, rq->rq_bcast_id);

	/* 
	 * We are either going to forward the REQUEST or generate a
	 * REPLY. Before we do anything, we make sure that the REVERSE
	 * route is in the route table.
	 */
	aodv_rt_entry *rt0; // rt0 is the reverse route 

	rt0 = rtable.rt_lookup(rq->rq_src);
	if (rt0 == 0) { /* if not in the route table */
		// create an entry for the reverse route.
		rt0 = rtable.rt_add(rq->rq_src);
	}

	rt0->rt_expire = max(rt0->rt_expire, (CURRENT_TIME + REV_ROUTE_LIFE));

	if ( (rq->rq_src_seqno > rt0->rt_seqno ) || ((rq->rq_src_seqno
			== rt0->rt_seqno) && (rq->rq_hop_count < rt0->rt_hops))) {
		// If we have a fresher seq no. or lesser #hops for the 
		// same seq no., update the rt entry. Else don't bother.
		rt_update(rt0, rq->rq_src_seqno, rq->rq_hop_count, ih->saddr(), 
		max(rt0->rt_expire, (CURRENT_TIME + REV_ROUTE_LIFE)));
		if (rt0->rt_req_timeout > 0.0) {
			// Reset the soft state and 
			// Set expiry time to CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT
			// This is because route is used in the forward direction,
			// but only sources get benefited by this change
			rt0->rt_req_cnt = 0;
			rt0->rt_req_timeout = 0.0;
			rt0->rt_req_last_ttl = rq->rq_hop_count;
			rt0->rt_expire = CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT;
		}

		/* Find out whether any buffered packet can benefit from the 
		 * reverse route.
		 * May need some change in the following code - Mahesh 09/11/99
		 */
		assert(rt0->rt_flags == RTF_UP);
		Packet *buffered_pkt;
		while ((buffered_pkt = rqueue.deque(rt0->rt_dst))) {
			if (rt0 && (rt0->rt_flags == RTF_UP)) {
				assert(rt0->rt_hops != INFINITY2);
				forward(rt0, buffered_pkt, NO_DELAY);
			}
		}
	}
	// End for putting reverse route in rt table


	/*
	 * We have taken care of the reverse route stuff.
	 * Now see whether we can send a route reply. 
	 */

	rt = rtable.rt_lookup(rq->rq_dst);

	// First check if I am the destination ..

	// 9. DRBT
	if ((rq->rq_bp != -1)&&(lookupband_bef_src(bande_bef, index))
			&& (lookupPile(mapile, ih->saddr()))) //Je suis BE et j'ai recu un flux QoS de mon voisin
	{
		bpBE = findband_src(bande_BE, index);
		dest = findband_dst(bande_BE, index); // retourne à partir de la source la destination
		//bplibre2 = findband(bande_aodv, index, dest);
		//bplibre3 = findband(bande_aodv, rq->rq_src, rq->rq_dst);

		//printf("0-Je suis %d de %d de %d vers %d bplibre %f\n",index,rq->rq_src,ih->saddr(),rq->rq_dst,rq->rq_bplibre);

		if (!lookupRREQ(rreq, rq->rq_src, rq->rq_dst, rq->rq_bp)) {

			insertRREQ(&rreq, rq->rq_src, rq->rq_dst, rq->rq_bp);

			hops = NETWORK_DIAMETER - ih->ttl_;
			if (hops >= 4)
				hops = 4;
			//bp_requis = rq->rq_bp*hops;


			if (rq->rq_bplibre > 0) {

				printf(
						"AAA-Je suis %d recv RREQ de %d Mon debit %f bplibre %f nbFlux_be %d : Arret de mon Best Effort\n",
						index, ih->saddr(), bpBE, rq->rq_bplibre,
						rq->rq_be_count);
				if (rq->rq_be_count != 0) {
					sendFalseReply(rq->rq_be_count, (double)bpBE, // Bande Passante BE (Timestamp)
							rq->rq_bplibre); // BpLibre Restante Aprés L'etablissement du flux
				} else {
					sendFalseReply( 1, (double)bpBE, // Bande Passante BE (Timestamp)
							rq->rq_bplibre); // BpLibre Restante Aprés L'etablissement du flux
				}
			} else {

				hops = NETWORK_DIAMETER - ih->ttl_;
				if (hops >= 4)
					hops = 4;
				//bp_requis = rq->rq_bp*hops;
				bp_requis = rq->rq_bp;

				bplibre = findband(bande_aodv, ih->saddr(), index);
				printf(
						"BBB-Je suis %d  vers %d Mon debit %f bplibre %f nbFlux_be %d libre %f: Arret de mon Best Effort\n",
						index, dest, bpBE, rq->rq_bplibre, rq->rq_be_count,
						bplibre - bp_requis);
				if (rq->rq_be_count != 0) {
					sendFalseReply(rq->rq_be_count, (double)bpBE, // Bande Passante BE (Timestamp)
							bplibre - bp_requis); // BpLibre Restante Aprés L'etablissement du flux
				} else {
					sendFalseReply( 1, (double)bpBE, // Bande Passante BE (Timestamp)
							bplibre -bp_requis); // BpLibre Restante Aprés L'etablissement du flux
				}

			}

			//Packet::free(p);

		}
	}

	/********************************************************************************/
	// end 9

	if (rq->rq_dst == index) {

		// 10. DRBT
		/******************************************************************************************************/
		/*                            Le flux QoS est accepté je dois prévenir les flux BE (stations cachées) : Hello           */

		//afficheband(bande_qos);
		if (chercheband(bande_qos, rq->rq_src, rq->rq_dst)) // Si j'ai récue un flux QoS
		{
			if (!lookupRREQ(rreq_sc, rq->rq_src, rq->rq_dst, rq->rq_bp)) {
				insertRREQ(&rreq_sc, rq->rq_src, rq->rq_dst, rq->rq_bp);
				debitQoS = rq->rq_bp*hops;
				emetteur = ih->saddr();
				compteur_be_sc = rq->rq_be_count;
				bplibre = findband(bande_aodv, ih->saddr(), index) - (rq->rq_bp
						* hops);
				//printf("bplibre %f rq->rq_bplibre %f\n",bplibre,rq->rq_bplibre);
				if ( (bplibre < rq->rq_bplibre && bplibre > 0)|| (rq->rq_bplibre <= 0 && bplibre > 0)  ) /* Si la bplibre est plus petite que le lien précedent */
{				rq->rq_bplibre = bplibre;
			}
			//afficheband(bande_aodv);
			printf("Hello : Je suis %d recu un RREQ de flux QoS avec %f prevenant de %d src %d et allant vers %d nbFlux_be %d hops %f bplibre %f : Je previent les FluxBE (stations cachées)\n", index,rq->rq_bp,ih->saddr(),rq->rq_src,rq->rq_dst,compteur_be_sc,hops,rq->rq_bplibre);
			bplibre_ = rq->rq_bplibre;

			/*  Sauvegarde FLUX QoS : ON */

			if(!lookupFLUX(flux_on_qos, id_flux, rq->rq_bplibre))
			{
				//printf("Hello index %d bplibre %f\n", index, rq->rq_bplibre);
				insertFLUX(&flux_on_qos, id_flux, rq->rq_bplibre);
				idFlux = id_flux; // Différencier Flux QoS et Flux BE (tj : -1)
				id_flux ++;
			}

		}
	}

	/********************************************************************************************/
	// end 10

#ifdef DEBUG
	fprintf(stderr, "%d - %s: destination sending reply\n",
			index, __FUNCTION__);
#endif // DEBUG
	// Just to be safe, I use the max. Somebody may have
	// incremented the dst seqno.
	seqno = max(seqno, rq->rq_dst_seqno)+1;
	if (seqno%2) seqno++;

	sendReply(rq->rq_src, // IP Destination
			1, // Hop Count
			index, // Dest IP Address
			seqno, // Dest Sequence Num
			// 11. DRBT
			idFlux,
			// end 11
			MY_ROUTE_TIMEOUT, // Lifetime
			rq->rq_timestamp,
			// 12. DRBT
			rq->rq_bplibre, 0 ); // bande passante libre min du flux QoS
			// end 12

	Packet::free(p);
}

// I am not the destination, but I may have a fresh enough route.

else if (rt && (rt->rt_hops != INFINITY2) &&
		(rt->rt_seqno >= rq->rq_dst_seqno)) {

	//assert (rt->rt_flags == RTF_UP);
	assert(rq->rq_dst == rt->rt_dst);
	//assert ((rt->rt_seqno%2) == 0);	// is the seqno even?


	sendReply(rq->rq_src,
			rt->rt_hops + 1,
			rq->rq_dst,
			rt->rt_seqno,
			// 13. DRBT
			-1,
			(u_int32_t) (rt->rt_expire - CURRENT_TIME),
			//             rt->rt_expire - CURRENT_TIME,
			rq->rq_timestamp,
			rq->rq_bplibre,0 );
			// end 13
	// Insert nexthops to RREQ source and RREQ destination in the
	// precursor lists of destination and source respectively
	rt->pc_insert(rt0->rt_nexthop); // nexthop to RREQ source
	rt0->pc_insert(rt->rt_nexthop); // nexthop to RREQ destination

#ifdef RREQ_GRAT_RREP  

	sendReply(rq->rq_dst,
			rq->rq_hop_count,
			rq->rq_src,
			rq->rq_src_seqno,
			// 14. DRBT
			-1,
			(u_int32_t) (rt->rt_expire - CURRENT_TIME),
			//             rt->rt_expire - CURRENT_TIME,
			rq->rq_timestamp,
			rq->rq_bplibre,0 );
			// end 14

#endif

	// TODO: send grat RREP to dst if G flag set in RREQ using rq->rq_src_seqno, rq->rq_hop_counT

	// DONE: Included gratuitous replies to be sent as per IETF aodv draft specification. As of now, G flag has not been dynamically used and is always set or reset in aodv-packet.h --- Anant Utgikar, 09/16/02.

	Packet::free(p);
}
/*
 * Can't reply. So forward the  Route Request
 */
else {
	// 15. DRBT
	if (rq->rq_bp != -1) /* Je forward un flux QoS */
	{

		bplibre = findband(bande_aodv,ih->saddr(),index) - (rq->rq_bp * hops);

		//printf("000-Je suis %d Forward RREQ src = %d dst = %d recu de %d bplibre %f = (libre %f - debit %f * hops %f)\n",index,rq->rq_src,rq->rq_dst,ih->saddr(),rq->rq_bplibre,findband(bande_aodv,ih->saddr(),index),rq->rq_bp,hops);

		//if (rq->rq_bplibre == 0)
		//rq->rq_bplibre = bplibre;
		if ( (bplibre < rq->rq_bplibre && bplibre> 0) || (rq->rq_bplibre <= 0 && bplibre> 0) ) /* Si la bplibre est plus petite que le lien précedent */
		{
			rq->rq_bplibre = bplibre;
		}

		//printf("I**********bplibre %f rq->rq_bplibre %f\n",bplibre, rq->rq_bplibre);
		//printf("111-Je suis %d Forward RREQ src = %d dst = %d recu de %d bplibre %f = (libre %f - debit %f * hops %f)\n",index,rq->rq_src,rq->rq_dst,ih->saddr(),rq->rq_bplibre,findband(bande_aodv,ih->saddr(),index),rq->rq_bp,hops);
	}
	// end 15


	ih->saddr() = index;
	ih->daddr() = IP_BROADCAST;
	rq->rq_hop_count += 1;
	// Maximum sequence number seen en route

	if (rt) rq->rq_dst_seqno = max(rt->rt_seqno, rq->rq_dst_seqno);
	forward((aodv_rt_entry*) 0, p, DELAY);
}

}

void AODV::recvReply(Packet *p) {
	//struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);
	aodv_rt_entry *rt;
	char suppress_reply = 0;
	double delay = 0.0;
	// 16. DRBT
	float bp;
	float bpBE = 0;
	float time1, time2;
	// end 16	

#ifdef DEBUG
	fprintf(stderr, "%d - %s: received a REPLY\n", index, __FUNCTION__);
#endif // DEBUG

	/*
	 *  Got a reply. So reset the "soft state" maintained for 
	 *  route requests in the request table. We don't really have
	 *  have a separate request table. It is just a part of the
	 *  routing table itself. 
	 */
	// Note that rp_dst is the dest of the data packets, not the
	// the dest of the reply, which is the src of the data packets.

	rt = rtable.rt_lookup(rp->rp_dst);

	/*
	 *  If I don't have a rt entry to this host... adding
	 */
	if (rt == 0) {
		rt = rtable.rt_add(rp->rp_dst);
	}

	/*
	 * Add a forward route table entry... here I am following 
	 * Perkins-Royer AODV paper almost literally - SRD 5/99
	 */

	if ( (rt->rt_seqno < rp->rp_dst_seqno) || // newer route 
			((rt->rt_seqno == rp->rp_dst_seqno) && (rt->rt_hops
					> rp->rp_hop_count))) { // shorter or better route

		// Update the rt entry 
		rt_update(rt, rp->rp_dst_seqno, rp->rp_hop_count, rp->rp_src,
				CURRENT_TIME + rp->rp_lifetime);

		// reset the soft state
		rt->rt_req_cnt = 0;
		rt->rt_req_timeout = 0.0;
		rt->rt_req_last_ttl = rp->rp_hop_count;

		if (ih->daddr() == index) { // If I am the original source
			// Update the route discovery latency statistics
			// rp->rp_timestamp is the time of request origination

			rt->rt_disc_latency[rt->hist_indx]
					= (CURRENT_TIME - rp->rp_timestamp)
							/ (double) rp->rp_hop_count;
			// increment indx for next time
			rt->hist_indx = (rt->hist_indx + 1) % MAX_HISTORY;

		}

		// 17. DRBT
		/******************************************************************************************************/
		/*                            Le flux QoS est accepté je dois prévenir les flux BE : Hello           */

		if (!lookupRREQ(rrep2, ih->saddr(), ih->daddr(), -1)) {
			insertRREQ(&rrep2, ih->saddr(), ih->daddr(), -1);
			printf(
					"Je suis %d recu un RREP de flux QoS prevenant de %d de %d et allant vers %d avec %f id_flux %d\n",
					index, ih->saddr(), rp->rp_src, ih->daddr(),
					rp->rp_bplibre, rp->rp_id_flux);

			if (!lookupFLUX(flux_on_qos, rp->rp_id_flux, rp->rp_bplibre)
					&& (rp->rp_id_flux != -1)) {
				//printf("Hello index %d bplibre %f id_flux %d\n", index, rp->rp_bplibre, rp->rp_id_flux);
				insertFLUX(&flux_on_qos, rp->rp_id_flux, rp->rp_bplibre);
			}

			bplibre_ = rp->rp_bplibre;
		}

		/******************************************************************************************************/
		/*                            Le flux BE est accepté je dois prévenir les flux QoS pour augmenter leurs nbFlux_be : Hello           */

		if (chercheband(bande_BE, ih->daddr(), rp->rp_src)
				&& lookupband_bef_src(bande_bef, index)) // Je suis BE et j'ai récu un flux BE 
		{

			//printf("Je suis %d recu un RREP de flux QoS prevenant de %d et allant vers %d\n",index,rp->rp_src,ih->daddr());

			if (!lookupRREQ(rrep, ih->daddr(), rp->rp_src, -1)) {
				insertRREQ(&rrep, ih->daddr(), rp->rp_src, -1);
				//debitQoS = findband(bande_qos,rq->rq_src,rq->rq_dst);
				compteur_be = 1;
				//printf(" Hello : Je suis %d recu un RREP prevenant de %d et allant vers %d\n",index,ih->daddr(),rp->rp_src);
			}

		}

		/********************************************************************************************************/
		// end 17


		/*
		 * Send all packets queued in the sendbuffer destined for
		 * this destination. 
		 * XXX - observe the "second" use of p.
		 */
		Packet *buf_pkt;
		while ((buf_pkt = rqueue.deque(rt->rt_dst))) {
			if (rt->rt_hops != INFINITY2) {
				assert(rt->rt_flags == RTF_UP);
				// Delay them a little to help ARP. Otherwise ARP 
				// may drop packets. -SRD 5/23/99
				forward(rt, buf_pkt, delay);
				delay += ARP_DELAY;
			}
		}
	} else {
		suppress_reply = 1;
	}

	/*
	 * If reply is for me, discard it.
	 */

	if (ih->daddr() == index || suppress_reply) {
		Packet::free(p);
	}
	/*
	 * Otherwise, forward the Route Reply.
	 */
	else {

		//printf("Je suis %d forward RREP de %d de %d vers %d vers %d\n",index,rp->rp_src,ih->saddr(),rp->rp_dst,ih->daddr());

		// Find the rt entry
		aodv_rt_entry *rt0 = rtable.rt_lookup(ih->daddr());
		// If the rt is up, forward
		if (rt0 && (rt0->rt_hops != INFINITY2)) {
			assert(rt0->rt_flags == RTF_UP);
			rp->rp_hop_count += 1;
			rp->rp_src = index;
			forward(rt0, p, NO_DELAY);
			// Insert the nexthop towards the RREQ source to 
			// the precursor list of the RREQ destination
			rt->pc_insert(rt0->rt_nexthop); // nexthop to RREQ source
		} else {
			// I don't know how to forward .. drop the reply. 
#ifdef DEBUG
			fprintf(stderr, "%s: dropping Route Reply\n", __FUNCTION__);
#endif // DEBUG
			drop(p, DROP_RTR_NO_ROUTE);
		}
	}
}

void AODV::recvError(Packet *p) {
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_error *re = HDR_AODV_ERROR(p);
	aodv_rt_entry *rt;
	u_int8_t i;
	Packet *rerr = Packet::alloc();
	struct hdr_aodv_error *nre = HDR_AODV_ERROR(rerr);

	nre->DestCount = 0;

	for (i=0; i<re->DestCount; i++) {
		// For each unreachable destination
		rt = rtable.rt_lookup(re->unreachable_dst[i]);
		if (rt && (rt->rt_hops != INFINITY2) && (rt->rt_nexthop == ih->saddr())
				&& (rt->rt_seqno <= re->unreachable_dst_seqno[i])) {
			assert(rt->rt_flags == RTF_UP);
			assert((rt->rt_seqno%2) == 0); // is the seqno even?
#ifdef DEBUG
			fprintf(stderr, "%s(%f): %d\t(%d\t%u\t%d)\t(%d\t%u\t%d)\n", __FUNCTION__,CURRENT_TIME,
					index, rt->rt_dst, rt->rt_seqno, rt->rt_nexthop,
					re->unreachable_dst[i],re->unreachable_dst_seqno[i],
					ih->saddr());
#endif // DEBUG
			rt->rt_seqno = re->unreachable_dst_seqno[i];
			rt_down(rt);

			// Not sure whether this is the right thing to do
			Packet *pkt;
			while ((pkt = ifqueue->filter(ih->saddr()))) {
				drop(pkt, DROP_RTR_MAC_CALLBACK);
			}

			// if precursor list non-empty add to RERR and delete the precursor list
			if (!rt->pc_empty()) {
				nre->unreachable_dst[nre->DestCount] = rt->rt_dst;
				nre->unreachable_dst_seqno[nre->DestCount] = rt->rt_seqno;
				nre->DestCount += 1;
				rt->pc_delete();
			}
		}
	}

	if (nre->DestCount > 0) {
#ifdef DEBUG
		fprintf(stderr, "%s(%f): %d\t sending RERR...\n", __FUNCTION__, CURRENT_TIME, index);
#endif // DEBUG
		sendError(rerr);
	} else {
		Packet::free(rerr);
	}

	Packet::free(p);
}

/*
 Packet Transmission Routines
 */

void AODV::forward(aodv_rt_entry *rt, Packet *p, double delay) {
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);

	if (ih->ttl_ == 0) {

#ifdef DEBUG
		fprintf(stderr, "%s: calling drop()\n", __PRETTY_FUNCTION__);
#endif // DEBUG
		drop(p, DROP_RTR_TTL);
		return;
	}

	if (ch->ptype() != PT_AODV && ch->direction() == hdr_cmn::UP
			&& ((u_int32_t)ih->daddr() == IP_BROADCAST)
			|| ((u_int32_t)ih->daddr() == here_.addr_)) {
		dmux_->recv(p, 0);
		return;
	}

	if (rt) {
		assert(rt->rt_flags == RTF_UP);
		rt->rt_expire = CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT;
		ch->next_hop_ = rt->rt_nexthop;
		ch->addr_type() = NS_AF_INET;
		ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction
	} else { // if it is a broadcast packet
		// assert(ch->ptype() == PT_AODV); // maybe a diff pkt type like gaf
		assert(ih->daddr() == (nsaddr_t) IP_BROADCAST);
		ch->addr_type() = NS_AF_NONE;
		ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction
	}

	if (ih->daddr() == (nsaddr_t) IP_BROADCAST) {
		// If it is a broadcast packet
		assert(rt == 0);
		/*
		 *  Jitter the sending of broadcast packets by 10ms
		 */
		Scheduler::instance().schedule(target_, p, 0.01 * Random::uniform());
	} else { // Not a broadcast packet 
		if (delay > 0.0) {
			Scheduler::instance().schedule(target_, p, delay);
		} else {
			// Not a broadcast packet, no delay, send immediately
			Scheduler::instance().schedule(target_, p, 0.);
		}
	}

}

void AODV::sendRequest(nsaddr_t dst) {
	// Allocate a RREQ packet 
	Packet *p = Packet::alloc();
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_request *rq = HDR_AODV_REQUEST(p);
	aodv_rt_entry *rt = rtable.rt_lookup(dst);
	// 18. DRBT
	float testband;
	// end 18

	assert(rt);

	/*
	 *  Rate limit sending of Route Requests. We are very conservative
	 *  about sending out route requests. 
	 */

	if (rt->rt_flags == RTF_UP) {
		assert(rt->rt_hops != INFINITY2);
		Packet::free((Packet *)p);
		return;
	}

	if (rt->rt_req_timeout > CURRENT_TIME) {
		Packet::free((Packet *)p);
		return;
	}

	// rt_req_cnt is the no. of times we did network-wide broadcast
	// RREQ_RETRIES is the maximum number we will allow before 
	// going to a long timeout.

	if (rt->rt_req_cnt > RREQ_RETRIES) {
		rt->rt_req_timeout = CURRENT_TIME + MAX_RREQ_TIMEOUT;
		rt->rt_req_cnt = 0;
		Packet *buf_pkt;
		while ((buf_pkt = rqueue.deque(rt->rt_dst))) {
			drop(buf_pkt, DROP_RTR_NO_ROUTE);
		}
		Packet::free((Packet *)p);
		return;
	}

	// 19. DRBT, can xem lai doan nay phai o duoi 20 DRBT hay khong
	testband = findband(bande_qos, index, dst);

	if (lookupRREQ(rreq2, rq->rq_src, rq->rq_dst, rq->rq_bp)
			&& (testband != -1 ) && (testband != 0)) {
		Packet::free((Packet *)p);
		return;
	} else {
		if ( (testband != -1 ) && (testband != 0)) {
			// Minh: 
			afficheband(bande_aodv);
			printf("MINH: testband=%f index=%d dst=%d\n", testband, index, dst);
			if (testband > findband(bande_aodv, index, dst) && findband(bande_aodv, index, dst)) {
				Packet::free((Packet *)p);
				return;
			}
			insertRREQ(&rreq2, rq->rq_src, rq->rq_dst, rq->rq_bp);
		}
	}
	// end 19

#ifdef DEBUG
	fprintf(stderr, "(%2d) - %2d sending Route Request, dst: %d\n",
			++route_request, index, rt->rt_dst);
#endif // DEBUG
	// Determine the TTL to be used this time. 
	// Dynamic TTL evaluation - SRD

	rt->rt_req_last_ttl = max(rt->rt_req_last_ttl,rt->rt_last_hop_count);

	if (0 == rt->rt_req_last_ttl) {
		// first time query broadcast
		ih->ttl_ = TTL_START;
	} else {
		// Expanding ring search.
		if (rt->rt_req_last_ttl < TTL_THRESHOLD)
			ih->ttl_ = rt->rt_req_last_ttl + TTL_INCREMENT;
		else {
			// network-wide broadcast
			ih->ttl_ = NETWORK_DIAMETER;
			rt->rt_req_cnt += 1;
		}
	}

	// remember the TTL used  for the next time
	rt->rt_req_last_ttl = ih->ttl_;

	// PerHopTime is the roundtrip time per hop for route requests.
	// The factor 2.0 is just to be safe .. SRD 5/22/99
	// Also note that we are making timeouts to be larger if we have 
	// done network wide broadcast before. 

	rt->rt_req_timeout = 2.0 * (double) ih->ttl_ * PerHopTime(rt);
	if (rt->rt_req_cnt > 0)
		rt->rt_req_timeout *= rt->rt_req_cnt;
	rt->rt_req_timeout += CURRENT_TIME;

	// Don't let the timeout to be too large, however .. SRD 6/8/99
	if (rt->rt_req_timeout > CURRENT_TIME + MAX_RREQ_TIMEOUT)
		rt->rt_req_timeout = CURRENT_TIME + MAX_RREQ_TIMEOUT;
	rt->rt_expire = 0;

#ifdef DEBUG
	fprintf(stderr, "(%2d) - %2d sending Route Request, dst: %d, tout %f ms\n",
			++route_request,
			index, rt->rt_dst,
			rt->rt_req_timeout - CURRENT_TIME);
#endif	// DEBUG

	// Fill out the RREQ packet 
	// ch->uid() = 0;
	ch->ptype() = PT_AODV;
	ch->size() = IP_HDR_LEN + rq->size();
	ch->iface() = -2;
	ch->error() = 0;
	ch->addr_type() = NS_AF_NONE;
	ch->prev_hop_ = index; // AODV hack

	ih->saddr() = index;
	ih->daddr() = IP_BROADCAST;
	ih->sport() = RT_PORT;
	ih->dport() = RT_PORT;

	// Fill up some more fields. 
	rq->rq_type = AODVTYPE_RREQ;
	rq->rq_hop_count = 1;
	rq->rq_bcast_id = bid++;
	rq->rq_dst = dst;
	// 20. DRBT
	rq->rq_be_count = nbFlux_be;

	/******************* sofiane *******************************/
	/*****  Remplir le champ rq->rq_bp avec la valeur souhaiter par le flux ********/

	//afficheband(bande_qos);
	testband = findband(bande_qos, index, dst);
	if ((testband != -1 ) && (testband != 0)) {
		//printf("source =%d destination =%d bp =%f\n",index,dst,testband);
		rq->rq_bp = testband;
		//if (rq->rq_bplibre == 0)
		//rq->rq_bplibre = DEBIT_MIN;

	} else {
		if (!lookupband_bef(bande_bef, index, dst))
			insertband_bef(&bande_bef, index, dst);
		rq->rq_bp = -1; //Flux Best Effort
	}

	/********************************************************************************/
	// end 20
	rq->rq_dst_seqno = (rt ? rt->rt_seqno : 0);
	rq->rq_src = index;
	seqno += 2;
	assert((seqno%2) == 0);
	rq->rq_src_seqno = seqno;
	rq->rq_timestamp = CURRENT_TIME;

	Scheduler::instance().schedule(target_, p, 0.);

}

void AODV::sendReply(nsaddr_t ipdst, u_int32_t hop_count, nsaddr_t rpdst,
		// 21. DRBT
		u_int32_t rpseq, u_int32_t idflux, u_int32_t lifetime,
		double timestamp, float bplibre, int falseReply) {
	// end 21
	Packet *p = Packet::alloc();
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);
	aodv_rt_entry *rt = rtable.rt_lookup(ipdst);
	// 22. DRBT
	float testband;
	// end 22

#ifdef DEBUG
	fprintf(stderr, "sending Reply from %d at %.2f\n", index, Scheduler::instance().clock());
#endif // DEBUG
	assert(rt);

	rp->rp_type = AODVTYPE_RREP;
	//rp->rp_flags = 0x00;
	rp->rp_hop_count = hop_count;
	rp->rp_dst = rpdst;
	rp->rp_dst_seqno = rpseq;
	rp->rp_src = index;
	rp->rp_lifetime = lifetime;
	rp->rp_timestamp = timestamp;
	// 23. DRBT
	rp->rp_bplibre = bplibre;
	rp->rp_false_RREP = falseReply;
	rp->rp_id_flux = idflux;
	// end 23

	// ch->uid() = 0;
	ch->ptype() = PT_AODV;
	ch->size() = IP_HDR_LEN + rp->size();
	ch->iface() = -2;
	ch->error() = 0;
	ch->addr_type() = NS_AF_INET;
	ch->next_hop_ = rt->rt_nexthop;
	ch->prev_hop_ = index; // AODV hack
	ch->direction() = hdr_cmn::DOWN;

	ih->saddr() = index;
	ih->daddr() = ipdst;
	ih->sport() = RT_PORT;
	ih->dport() = RT_PORT;
	ih->ttl_ = NETWORK_DIAMETER;

	Scheduler::instance().schedule(target_, p, 0.);

}

// 24. DRBT
void AODV::sendFalseReply(int nbFlux_be, double bpBE, float bplibre) {
	Packet *p = Packet::alloc();
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);
	//aodv_rt_entry *rt = rtable.rt_lookup(ipdst);

#ifdef DEBUG
	fprintf(stderr, "sending Reply from %d at %.2f\n", index, Scheduler::instance().clock());
#endif // DEBUG
	// assert(rt);

	rp->rp_type = AODVTYPE_RREP;
	//rp->rp_flags = 0x00;
	rp->rp_false_RREP = 1;
	rp->rp_hop_count = nbFlux_be;
	rp->rp_timestamp = bpBE;
	rp->rp_bplibre = bplibre;
	printf("SendFalseReply: nbBE=%d, bpBE=%f, bplibre=%f\n", nbFlux_be, bpBE, bplibre);

	// ch->uid() = 0;
	ch->ptype() = PT_AODV;
	ch->size() = IP_HDR_LEN + rp->size();
	ch->iface() = -2;
	ch->error() = 0;
	ch->addr_type() = NS_AF_INET;
	//ch->next_hop_ = rt->rt_nexthop;
	ch->prev_hop_ = index; // AODV hack
	ch->direction() = hdr_cmn::DOWN;

	ih->saddr() = index;
	// ih->daddr() = ipdst;
	ih->sport() = RT_PORT;
	ih->dport() = RT_PORT;
	ih->ttl_ = NETWORK_DIAMETER;
	Scheduler::instance().schedule(target_, p, 0.);

}
// end 24

void AODV::sendError(Packet *p, bool jitter) {
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_error *re = HDR_AODV_ERROR(p);

#ifdef ERROR
	fprintf(stderr, "sending Error from %d at %.2f\n", index, Scheduler::instance().clock());
#endif // DEBUG
	// 25. DRBT
	printf("EROOR %d %f\n", index, CURRENT_TIME);
	// end 25

	re->re_type = AODVTYPE_RERR;
	//re->reserved[0] = 0x00; re->reserved[1] = 0x00;
	// DestCount and list of unreachable destinations are already filled

	// ch->uid() = 0;
	ch->ptype() = PT_AODV;
	ch->size() = IP_HDR_LEN + re->size();
	ch->iface() = -2;
	ch->error() = 0;
	ch->addr_type() = NS_AF_NONE;
	ch->next_hop_ = 0;
	ch->prev_hop_ = index; // AODV hack
	ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction

	ih->saddr() = index;
	ih->daddr() = IP_BROADCAST;
	ih->sport() = RT_PORT;
	ih->dport() = RT_PORT;
	ih->ttl_ = 1;

	// Do we need any jitter? Yes
	if (jitter)
		Scheduler::instance().schedule(target_, p, 0.01*Random::uniform());
	else
		Scheduler::instance().schedule(target_, p, 0.0);

}

/*
 Neighbor Management Functions
 */

void AODV::sendHello() {
	Packet *p = Packet::alloc();
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_reply *rh = HDR_AODV_REPLY(p);
	// 26. DRBT
	int i;
	// end 26

#ifdef DEBUG
	fprintf(stderr, "sending Hello from %d at %.2f\n", index, Scheduler::instance().clock());
#endif // DEBUG
	rh->rp_type = AODVTYPE_HELLO;
	//rh->rp_flags = 0x00;
	rh->rp_hop_count = 1;
	rh->rp_dst = index;
	rh->rp_dst_seqno = seqno;
	rh->rp_lifetime = (1 + ALLOWED_HELLO_LOSS) * HELLO_INTERVAL;

	// 27. DRBT
	rh->rp_bp = debitQoS;
	rh->rp_emetteur = emetteur;
	rh->rp_be_count = compteur_be;
	rh->rp_bplibre_ = bplibre_;
	//if (rh->rp_bplibre_ =! -1)
	//printf("1. Minh test: Hello from %d rh->rp_bplibre=%f, rh->rp_be_count=%d\n, debit desiree=%f\n",index, bplibre_, compteur_be, debitQoS);
	/* 
	 if (bplibre_ != -1)
	 bplibre_ = -1;
	 */
	if (emetteur != -1)
		rh->rp_be_count = compteur_be_sc;
	if (debitQoS != -1)
		debitQoS = -1;
	if (emetteur != -1)
		emetteur = -1;
	if (compteur_be_sc != -1)
		compteur_be_sc = -1;

	/*
	 * Augmentation de débit
	 */

	tailleFluxQoS = length(flux_on_qos);
	rh->rp_ID_flux [0] = tailleFluxQoS; /* Stock le nb des Flux QoS dans rp_ID_flux [0] */
	for (i=1; i <= tailleFluxQoS; i++) {
		if (findFluxID(flux_on_qos, i) == testFlux) {
			rh->rp_bp_flux [i] = DEBIT_MIN; // ? why DEBIT_MIN
			rh->rp_ID_flux [i] = testFlux;
			printf("index %d idFlux %d bpFlux %f\n", index, rh->rp_ID_flux [i], rh->rp_bp_flux [i]);
		} else {
			if (rh->rp_ID_flux [i] != -1) {
				rh->rp_bp_flux [i] = findFluxBP(flux_on_qos, i);
				rh->rp_ID_flux [i] = findFluxID(flux_on_qos, i);
			}
		}
	}

	//printf("index %d idFlux %d bpFlux %f\n", index, rh->rp_ID_flux [1], rh->rp_bp_flux [1]);

	/*
	 * Flux QoS : stop
	 */
	rh->rp_flux_stop = testFlux;
	if ( (testFlux != -1) && (testFlux != 0)) {
		testFlux = -1;
		printf("index %d id supp %d\n", index, suppFLUX(&flux_on_qos));
	}
	// end 27

	// ch->uid() = 0;
	ch->ptype() = PT_AODV;
	ch->size() = IP_HDR_LEN + rh->size();
	ch->iface() = -2;
	ch->error() = 0;
	ch->addr_type() = NS_AF_NONE;
	ch->prev_hop_ = index; // AODV hack

	ih->saddr() = index;
	ih->daddr() = IP_BROADCAST;
	ih->sport() = RT_PORT;
	ih->dport() = RT_PORT;
	ih->ttl_ = 1;

	Scheduler::instance().schedule(target_, p, 0.0);
}

void AODV::recvHello(Packet *p) {
	// 28. DRBT
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);
	AODV_Neighbor *nb;
	float bpBE;
	int dest;
	//float bplibre2;
	float bplibreMax;
	int i;

	bpBE = findband_src(bande_BE, index);

	//printf("HELLO PACKET src = %d dst = %d bplibre = %f\n",index,rp->rp_dst,rp->rp_bplibre);

	if (!lookupband(bande_aodv, index, rp->rp_dst, rp->rp_bplibre)) {
		insertband(&bande_aodv, index, rp->rp_dst, rp->rp_bplibre);
	}

	/*
	 *  Augmentation du débit
	 */

	if (rp->rp_ID_flux[0] != 0) { // nombre de flux QoS > 0
		//printf("So flux: %d\n", rp->rp_ID_flux[0]);
		for (i=1; i<=rp->rp_ID_flux[0]; i++) {

			/*  Sauvegarde par l'Emetteur des flux BE les flux QoS */

			if (lookupband_bef_src(bande_bef, index)
					&& (rp->rp_ID_flux[i] != 0)) {

				if (!lookupFLUX(flux_on_be, rp->rp_ID_flux[i],
						rp->rp_bp_flux[i])) {
					insertFLUX(&flux_on_be, rp->rp_ID_flux[i],
							rp->rp_bp_flux[i]);
					//afficheFLUX(flux_on_be);
				}

				if (rp->rp_bp_flux[i] < minBp) {
					printf("Hello : recv by %d from %d (rp_bp_min %f < minBp %f)\n",
							index, rp->rp_dst, rp->rp_bp_flux[i], minBp);
					if (rp->rp_be_count != 0) {
						sendFalseReply(rp->rp_be_count, bpBE, // Bande Passante BE (Timestamp)
								rp->rp_bp_flux[i]); // BpLibre Restante En prenant en compte les stations cachées
					} else {
						sendFalseReply( 1, bpBE, // Bande Passante BE (Timestamp)
								rp->rp_bp_flux[i]); // BpLibre Restante En prenant en compte les stations cachées
					}
					minBp = rp->rp_bp_flux[i];
				}
			}

			/*  L'Emetteur du flux BE augmente son débit */

			if (lookupband_bef_src(bande_bef, index) && (rp->rp_bp_flux[i]
					== DEBIT_MIN)) /* Emetteur de flux BE */
			{
				printf("Hello : recv by %d from %d fluxQoS : STOP %d\n", index,
						rp->rp_dst, rp->rp_flux_stop);
				if (rp->rp_be_count != 0) {
					sendFalseReply(rp->rp_be_count, bpBE, // Bande Passante BE (Timestamp)
							rp->rp_bp_flux[i]); // BpLibre Restante En prenant en compte les stations cachées
					printf("MINH: nbBe=%d, bpBE=%f, rp->rp_bp_flux[%d]=%f\n", rp->rp_be_count, bpBE, i, rp->rp_bp_flux[i]);
				} else {
					sendFalseReply( 1, bpBE, // Bande Passante BE (Timestamp)
							rp->rp_bp_flux[i]); // BpLibre Restante En prenant en compte les stations cachées
					printf("2 MINH: nbBe=%d, bpBE=%f, rp->rp_bp_flux[%d]=%f\n", rp->rp_be_count, bpBE, i, rp->rp_bp_flux[i]);
				}

				minBp = DEBIT_MIN;
				printf("index %d id supp %d\n", index, suppFLUX(&flux_on_be));

			}

		}
	}

	/****************************************************************************************/
	/**********  Augmentation du débit : Chaque noeud QoS alerte son voisin sur le chemin *******/

	//if (rp->rp_flux_stop == 1)
	if (findFluxID(flux_on_qos, rp->rp_flux_stop)) {
		if (testFlux != -1) {
			testFlux = rp->rp_flux_stop;
			//bplibre2 = findband(bande_aodv,rp->rp_dst,index);     
			printf("Hello recv by %d from %d fluxQos %d bplibre %f\n", index,
					rp->rp_dst, rp->rp_flux_stop, rp->rp_bp_flux[1]);

		}
	}

	/************************************************************************************/
	/*              Table de Voisinage               */

	if (!lookupPile(mapile, rp->rp_dst)) {
		insertPile(&mapile, rp->rp_dst);
		//affichePile(mapile);
	}

	/*              Nombre de Flux BE               */

	if (chercheband_src(bande_qos, index)) // Je suis QoS j'ai recu une info sur un flux BE
	{
		//printf("source =%d destination =%d\n",index,rp->rp_dst);
		if ( (rp->rp_be_count == 1) && (!lookupPile(mapile_be, rp->rp_dst))) {
			insertPile(&mapile_be, rp->rp_dst);
			//printf("source =%d destination =%d\n",index,rp->rp_dst);
			nbFlux_be ++;
		}
	}

	/************************************************************************************/
	/*           Envoyer un faux RREP pour la couche MAC procedure RECV  : STATIONS CACHEES*/

	bpBE = findband_src(bande_BE, index);

	if ((rp->rp_bp != -1) && (rp->rp_emetteur != -1) && (lookupband_bef_src(
			bande_bef, index))) //Je suis BE et j'ai réçu un flux QoS de station cachée
	{

		if (!lookupPile(mapile, rp->rp_emetteur)) {
			printf(
					"A-ST : Je suis %d recv Hello avec bp %f de %d et nbFlux_be %d: Arret de mon Best Effort\n",
					index, rp->rp_bp, rp->rp_emetteur, rp->rp_be_count);
			bplibreMax = calcul(rp->rp_bp);
			printf("bplibreMax %f\n", bplibreMax);

			if (bplibreMax < minBp) {

				testStCachees = true;
				if (rp->rp_be_count != 0) {
					sendFalseReply(rp->rp_be_count, bpBE, // Bande Passante BE (Timestamp)
							bplibreMax); // BpLibre Restante En prenant en compte les stations cachées
				} else {
					sendFalseReply( 1, bpBE, // Bande Passante BE (Timestamp)
							bplibreMax); // BpLibre Restante En prenant en compte les stations cachées
				}
				minBp = bplibreMax;

			}

		}

	}

	/******************************************************************/
	/*                          bplibre dans le RREP                 */

	if ((rp->rp_bplibre_ != -1) && (rp->rp_bplibre_ != 0) && (rp->rp_bplibre_
			> 0) && (lookupband_bef_src(bande_bef, index))) //Je suis BE et j'ai réçu un flux QoS de station cachée
	{
		//printf("Hello : Je suis %d recv Hello de %d avec %f : Arret de mon Best Effort\n",index,rp->rp_dst,rp->rp_bplibre_);

		if (!lookupRREQ(hello, -1, rp->rp_dst, rp->rp_bplibre_)
				&& !testStCachees) /* Eviter de recevoir deux fois la même bplibre de deux voisins */
		{
			insertRREQ(&hello, -1, rp->rp_dst, rp->rp_bplibre_);
			printf("Hello : Je suis %d recv Hello de %d avec %f nbFlux %d: Arret de mon Best Effort\n",
					index, rp->rp_dst, rp->rp_bplibre_, rp->rp_be_count);

			if (rp->rp_bplibre_ < minBp) {
				if (rp->rp_be_count != 0) {
					sendFalseReply(rp->rp_be_count, bpBE, rp->rp_bplibre_);
				} else {
					sendFalseReply( 1, bpBE, rp->rp_bplibre_);
				}
				minBp = rp->rp_bplibre_;
			}
		}

	}
	/****************************************************************/

	testStCachees = false;
	// end 28
	nb = nb_lookup(rp->rp_dst);
	if (nb == 0) {
		nb_insert(rp->rp_dst);
	} else {
		nb->nb_expire = CURRENT_TIME +
		(1.5 * ALLOWED_HELLO_LOSS * HELLO_INTERVAL);
	}

	Packet::free(p);
}

void AODV::nb_insert(nsaddr_t id) {
	AODV_Neighbor *nb = new AODV_Neighbor(id);

	assert(nb);
	nb->nb_expire = CURRENT_TIME +
	(1.5 * ALLOWED_HELLO_LOSS * HELLO_INTERVAL);
	LIST_INSERT_HEAD(&nbhead, nb, nb_link);
	seqno += 2; // set of neighbors changed
	assert((seqno%2) == 0);
}

AODV_Neighbor* AODV::nb_lookup(nsaddr_t id) {
	AODV_Neighbor *nb = nbhead.lh_first;

	for (; nb; nb = nb->nb_link.le_next) {
		if (nb->nb_addr == id)
			break;
	}
	return nb;
}

/*
 * Called when we receive *explicit* notification that a Neighbor
 * is no longer reachable.
 */
void AODV::nb_delete(nsaddr_t id) {
	AODV_Neighbor *nb = nbhead.lh_first;

	log_link_del(id);
	seqno += 2; // Set of neighbors changed
	assert((seqno%2) == 0);

	for (; nb; nb = nb->nb_link.le_next) {
		if (nb->nb_addr == id) {
			LIST_REMOVE(nb, nb_link);
			delete nb;
			break;
		}
	}

	handle_link_failure(id);

}

// 29. DRBT
void AODV::insertband(Band_Aodv **p, int src, int dst, float uz) {
	Band_Aodv *e = (Band_Aodv *)malloc(sizeof(Band_Aodv));
	if (!e)
		return; /* Allocation echouee */
	e->src = src;
	e->dst = dst;
	e->uz = uz;
	//e->id = id;
	e->next = *p;
	*p = e;
}

bool AODV::lookupband(Band_Aodv *p, int src, int dst, float uz) {
	if (p == NULL)
		return false;
	while (p) {
		if ((p->src==src)&&(p->dst==dst)) {
			p->uz=uz;
			return true;
		}
		p=p->next;
	}
	return false;

}

bool AODV::chercheband(Band_Aodv *p, int src, int dst) {
	if (p == NULL)
		return false;
	while (p) {
		if ((p->src==src)&&(p->dst==dst)) {
			//p->uz=uz;
			return true;
		}
		p=p->next;
	}
	return false;

}

bool AODV::chercheband_src(Band_Aodv *p, int src) {
	if (p == NULL)
		return false;
	while (p) {
		if (p->src==src) {
			//p->uz=uz;
			return true;
		}
		p=p->next;
	}
	return false;

}

float AODV::findband(Band_Aodv *p, int src, int dst) {
	if (p == NULL)
		return false;
	while (p) {
		if ((p->src == src) && (p->dst == dst))
			return (p->uz);
		p=p->next;

	}
	return 0;
}

float AODV::findband_src(Band_Aodv *p, int src) {
	if (p == NULL)
		return false;
	while (p) {
		if (p->src == src)
			return (p->uz);
		p=p->next;

	}
	return 0;
}

int AODV::findband_dst(Band_Aodv *p, int src) {
	if (p == NULL)
		return false;
	while (p) {
		if (p->src == src)
			return (p->dst);
		p=p->next;

	}
	return 0;
}

void AODV::afficheband(Band_Aodv *p) {
	while (p) {
		printf("Src = %d Dst = %d Blibre =%f\n", p->src, p->dst, p->uz);
		p=p->next;
		printf("********\n");
	}
	printf("*****************************\n\n");
}

void AODV::insertband_bef(Band_Bef **p, int src, int dst) {
	Band_Bef *e = (Band_Bef *)malloc(sizeof(Band_Bef));
	if (!e)
		return; /* Allocation echouee */
	e->src = src;
	e->dst = dst;
	//e->uz = uz;
	e->next = *p;
	*p = e;
}

bool AODV::lookupband_bef(Band_Bef *p, int src, int dst) {
	if (p == NULL)
		return false;
	while (p) {
		if ((p->src==src)&&(p->dst==dst)) {
			//p->uz=uz;
			return true;
		}
		p=p->next;
	}
	return false;

}

bool AODV::lookupband_bef_src(Band_Bef *p, int src) {
	if (p == NULL)
		return false;
	while (p) {
		if ( (p->src==src) && (!((p->src==0) && (p->dst==0)))) {
			//p->uz=uz;
			return true;
		}
		p=p->next;
	}
	return false;

}

void AODV::afficheband_bef(Band_Bef *p) {
	while (p) {
		printf("Src = %d Dst = %d \n", p->src, p->dst);
		p=p->next;
		printf("********\n");
	}
	printf("*****************************\n\n");
}

void AODV::insertPile(Pile_ **p, int src) {

	Pile_ *e = (Pile_ *)malloc(sizeof(Pile_));
	if (!e)
		return;
	e->src = src;
	e->next = *p;
	*p = e;
}

bool AODV::lookupPile(Pile_ *p, int src) {

	if (p==NULL)
		return false;
	while (p) {
		if (p->src == src)
			return true;
		p = p->next;
	}
	return false;
}

void AODV::affichePile(Pile_ *p) {

	while (p) {
		printf("Je suis %d Mon voisin %d\n", index, p->src);
		p=p->next;
		printf("*********\n");
	}
	printf("**********************************\n\n");
}

void AODV::insertRREQ(RREQ_ **p, int src, int dst, float uz) {

	RREQ_ *e = (RREQ_ *)malloc(sizeof(RREQ_));
	if (!e)
		return;
	e->src = src;
	e->dst = dst;
	e->uz = uz;
	e->next = *p;
	*p = e;
}

bool AODV::lookupRREQ(RREQ_ *p, int src, int dst, float uz) {

	if (p==NULL)
		return false;
	while (p) {
		if (p->src == src && p->dst == dst && p->uz == uz)
			return true;
		p = p->next;
	}
	return false;
}

void AODV::afficheRREQ(RREQ_ *p) {

	while (p) {
		printf("RREQ de %d vers %d avec %f\n", p->src, p->dst, p->uz);
		p=p->next;
		printf("*********\n");
	}
	printf("**********************************\n\n");
}

/*
 * ...HELLO : Flux QoS ON 
 */

void AODV::insertFLUX(FLUX_ **p, int id, float uz) {

	FLUX_ *e = (FLUX_ *)malloc(sizeof(FLUX_));
	if (!e)
		return;
	e->id = id;
	e->uz = uz;
	e->next = *p;
	*p = e;
}

int AODV::suppFLUX(FLUX_ **p) {
	int id;
	FLUX_ *tmp;
	if (!*p)
		return -1; /* Retourne -1 si la pile est vide. */
	tmp = (*p)->next;
	id = (*p)->id;
	free(*p);
	*p = tmp; /* Le pointeur pointe sur le dernier élément. */
	return id; /* Retourne la valeur soutirée de la pile. */
}

bool AODV::lookupFLUX(FLUX_ *p, int id, float uz) {

	if (p==NULL)
		return false;
	while (p) {
		if (p->id == id) {
			p->uz = uz;
			return true;
		}
		p = p->next;
	}
	return false;
}

int AODV::length(FLUX_ *p) {
	int taille = 0;
	if (p==NULL)
		return 0;
	while (p) {
		if (p->id > 0)
			taille++;
		p = p->next;
	}
	return taille;
}

int AODV::findFluxID(FLUX_ *p, int i) {
	int id = 0;
	if (p == NULL)
		return 0;
	while (p) {
		id++;
		if (id == i)
			return p->id;
		p=p->next;

	}
	return 0;
}

float AODV::findFluxBP(FLUX_ *p, int i) {
	int id = 0;
	if (p == NULL)
		return 0;
	while (p) {
		id++;
		if (id == i)
			return p->uz;
		p=p->next;

	}
	return 0;
}

void AODV::afficheFLUX(FLUX_ *p) {

	while (p) {
		printf("FLUX n° %d avec %f\n", p->id, p->uz);
		p=p->next;
		printf("*********\n");
	}
	printf("**********************************\n\n");
}

// Dunno why did we creat that function
float AODV::calcul(float x) {
	float bplibre;
	float i;
	i =1.00-(x/1600.00);
	//printf("i %f\n",i);
	//bplibre = 240 *Puissance((1-(1/1600)*x),3)+ 49*Puissance((1-(1/1600)*x),2)+ 668-(167/400)*x; 
	//bplibre = 240*Puissance((1-(1/1600)*x),3)+ 49*Puissance((1-(1/1600)*x),2)+ 668*(1-(1/1600)*x);
	bplibre = 240*pow(i, 3)+ 49*pow(i, 2)+ 668*(i);
	return bplibre;
}

/*
 *   Test if I'm a receiver BE flow & return @ SRC BE if True 
 */

int AODV::testBestEffort(Band_Aodv *p, int index) {
	aodv_rt_entry *rt1;
	if (p == NULL)
		return -1;
	while (p) {
		if (p->src == 0 && p->dst == 0 && p->uz == 0)
			return -1;
		rt1 = rtable.rt_lookup(p->src);
		if (rt1 != 0)
			return (p->src);
		p=p->next;
	}
	return -1;
}
// end 29


/*
 * Purges all timed-out Neighbor Entries - runs every
 * HELLO_INTERVAL * 1.5 seconds.
 */
void AODV::nb_purge() {
	AODV_Neighbor *nb = nbhead.lh_first;
	AODV_Neighbor *nbn;
	double now= CURRENT_TIME;

	for (; nb; nb = nbn) {
		nbn = nb->nb_link.le_next;
		if (nb->nb_expire <= now) {
			nb_delete(nb->nb_addr);
		}
	}

}
